#include "MemMonitor.h"

// 初始化类静态成员
float MemMonitor::m_warnProportion = 0.4;
std::condition_variable MemMonitor::m_conditionVb;
std::mutex MemMonitor::m_mutex;

MemMonitor::MemMonitor()
{
}

MemMonitor::~MemMonitor()
{
    m_mutex.unlock();
}

void MemMonitor::startThread()
{
    // 内存检测线程
    std::thread threadDetect(threadMemoryDetect);
    // 内存回收线程
    std::thread threadRecover(threadMemoryRecover);

    threadDetect.join();
    threadRecover.join();
}

void MemMonitor::threadMemoryRecover()
{
    string threadName = "threadMemRecycle";
    pthread_setname_np(pthread_self(), threadName.substr(0, 15).c_str());

    while(1)
    {
        printf("Wait Notify......\n");
        std::unique_lock<std::mutex> uqLock(m_mutex);
        m_conditionVb.wait(uqLock);

        // 解除休眠后进行内存回收操作
        printf("Ready to Recover !!!!!!\n");
        recycleMem();

        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

void MemMonitor::threadMemoryDetect()
{
    string threadName = "threadMemDetect";
    pthread_setname_np(pthread_self(), threadName.substr(0, 15).c_str());

    while(1)
    {
        std::unique_lock<std::mutex> uqLock(m_mutex);
        printf("Detecting......\n");
        // 是否内存使用已经达到警戒
        if ( isMemUseWarning() )
        {
            printf("Notify threadMemoryRecover !!!\n");
            // 唤醒回收线程对内存进行回收
            m_conditionVb.notify_all();
            uqLock.unlock();
        }
        printf("\n");
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

bool MemMonitor::isMemUseWarning()
{
    // 系统内存信息
    MEM_OCCUPY mem_stat;
    get_memoccupy((MEM_OCCUPY *)&mem_stat);

    //获取已使用内存情况
    float memUsed = ( (mem_stat.MemTotal - mem_stat.MemFree)*1.0 / (1024*1024)* 1.0 );

    // 内存使用大于等于警告比例使用情况下，开始进行回收操作
    float memWarnVal = (mem_stat.MemTotal * 1.0) / ( 1024*1024) * 1.0;
    float memTotal = (mem_stat.MemTotal *1.0) / (1024*1024) * 1.0;
    std::cout <<"MemTotal: " << (round(memTotal * 10) / 10) << " G |MemUsed: " << (round(memUsed * 10) / 10) <<  " G"
             <<" | memWarnVal: " << (round(memWarnVal * m_warnProportion * 10) / 10) << " G\n";
    return (round(memUsed * 10) / 10) >= (round(memWarnVal * m_warnProportion * 10) / 10);
}

int MemMonitor::recycleMem()
{
    int res = system("echo 1 > /proc/sys/vm/drop_caches && echo 2 > /proc/sys/vm/drop_caches && echo 3 > /proc/sys/vm/drop_caches");
    std::cout <<"Run system res: " << res << endl;
    if ( res != 0 )
    {
        printf("Run system error: %s\n", strerror(errno));
    }
    return res;
}
